﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Gmantis.Controls.Chart
{
    public enum SelectionAction
    {
        None,
        MouseDown,
        LeftMouseDown,
        RightMouseDown,
        MouseOver
    }

    public enum Aggregate
    {
        None,
        Sum,
        Count,
        Average,
        Minimum,
        Maximum,
        Variance,
        VariancePop,
        StandardDeviation,
        StandardDeviationPop
    }

    [ContentProperty("Children")]
    public class ChartData : DependencyObject
    {
        // Fields
        private DataSeriesCollection _children;
        private Binding _nameBinding;
        private object[] _namesInternal;
        internal bool clearBuffer;
        private int currentIndex = -1;
        private Chart handlers;
        public static readonly DependencyProperty ItemNamesProperty = Utils.RegisterProperty("ItemNames", typeof(IEnumerable), typeof(ChartData), new PropertyChangedCallback(ChartData.OnItemNamesChanged));
        public static readonly DependencyProperty ItemsSourceProperty = Utils.RegisterProperty("ItemsSource", typeof(IEnumerable), typeof(ChartData), new PropertyChangedCallback(ChartData.OnItemsSourceChanged));
        public static readonly DependencyProperty LoadAnimationProperty = DependencyProperty.Register("LoadAnimation", typeof(PlotElementAnimation), typeof(ChartData), new PropertyMetadata(null));
        internal bool notify = true;
        public static readonly DependencyProperty RendererProperty = Utils.RegisterProperty("Renderer", typeof(IRenderer), typeof(ChartData), new PropertyChangedCallback(ChartData.OnRendererChanged));
        public static readonly DependencyProperty SelectionActionProperty = DependencyProperty.Register("SelectionAction", typeof(SelectionAction), typeof(ChartData), new PropertyMetadata(SelectionAction.None, new PropertyChangedCallback(ChartData.OnSelectionActionChanged)));
        public static readonly DependencyProperty SeriesItemsSourceProperty = DependencyProperty.Register("SeriesItemsSource", typeof(IEnumerable), typeof(ChartData), new PropertyMetadata(null, new PropertyChangedCallback(ChartData.OnSeriesItemsSourceChanged)));
        public static readonly DependencyProperty SeriesItemTemplateProperty = DependencyProperty.Register("SeriesItemTemplate", typeof(DataTemplate), typeof(ChartData), new PropertyMetadata(null, new PropertyChangedCallback(ChartData.OnSeriesItemTemplateChanged)));

        // Events
        public event EventHandler DataChanged;

        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
        public event PropertyChangedEventHandler PropertyChanged;

        // Methods
        private void _children_Changed(object sender, EventArgs e)
        {
            this.FireDataChanged(this, new PropertyChangedEventArgs("Children"));
        }

        internal void AddSeries(IDataSeriesInfo ser)
        {
            DataSeries series = (DataSeries)ser;
            series.ParentData = this;
            series.PropertyChanged += new PropertyChangedEventHandler(this.ChartData_PropertyChanged);
        }

        private void AttachHandlers()
        {
            if (((this.handlers == null) && (this.SelectionAction != SelectionAction.None)) && (this.Renderer != null))
            {
                Chart visual = this.Renderer.Visual as Chart;
                if (visual != null)
                {
                    visual.MouseLeftButtonDown += new MouseButtonEventHandler(this.chart_MouseLeftButtonDown);
                    visual.MouseRightButtonDown += new MouseButtonEventHandler(this.chart_MouseRightButtonDown);
                    visual.MouseMove += new MouseEventHandler(this.chart_MouseMove);
                    this.handlers = visual;
                }
            }
            if (this.handlers != null)
            {
                if (this.SelectionAction == SelectionAction.MouseOver)
                {
                    this.handlers.CaptureMouse();
                }
                else
                {
                    this.handlers.ReleaseMouseCapture();
                }
            }
        }

        private void chart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if ((this.SelectionAction == SelectionAction.LeftMouseDown) || (this.SelectionAction == SelectionAction.MouseDown))
            {
                this.HandleMouseEvent(sender, e);
            }
        }

        private void chart_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.SelectionAction == SelectionAction.MouseOver)
            {
                this.HandleMouseEvent(sender, e);
            }
        }

        private void chart_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            if ((this.SelectionAction == SelectionAction.RightMouseDown) || (this.SelectionAction == SelectionAction.MouseDown))
            {
                this.HandleMouseEvent(sender, e);
            }
        }

        private void ChartData_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.FireDataChanged(this, EventArgs.Empty);
        }

        private void ChartData_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.FireDataChanged(this, EventArgs.Empty);
        }

        private void CollectionViewCurrentChanged(object sender, EventArgs e)
        {
            this.UpdateSelection(true);
        }

        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
        public bool CreateDesignTimeData()
        {
            bool flag = false;
            if (this.Children.Count == 0)
            {
                DataSeries item = new DataSeries
                {
                    Label = "Series 1",
                    ValuesSource = new double[] { 20.0, 22.0, 19.0, 24.0, 25.0 }
                };
                this.Children.Add(item);
                item = new DataSeries
                {
                    Label = "Series 2",
                    ValuesSource = new double[] { 8.0, 12.0, 10.0, 12.0, 15.0 }
                };
                this.Children.Add(item);
                flag = true;
            }
            return flag;
        }

        private void DetachHandlers()
        {
            if (this.handlers != null)
            {
                Chart handlers = this.handlers;
                if (handlers != null)
                {
                    handlers.ReleaseMouseCapture();
                    handlers.MouseLeftButtonDown -= new MouseButtonEventHandler(this.chart_MouseLeftButtonDown);
                    handlers.MouseRightButtonDown -= new MouseButtonEventHandler(this.chart_MouseRightButtonDown);
                    handlers.MouseMove -= new MouseEventHandler(this.chart_MouseMove);
                    this.handlers = null;
                }
            }
        }

        private void FireDataChanged(object sender, EventArgs e)
        {
            if (this.notify)
            {
                if (this.DataChanged != null)
                {
                    this.DataChanged(sender, e);
                }
                if (this.PropertyChanged != null)
                {
                    PropertyChangedEventArgs args = e as PropertyChangedEventArgs;
                    if (args != null)
                    {
                        this.PropertyChanged(this, args);
                    }
                    else
                    {
                        this.PropertyChanged(this, new PropertyChangedEventArgs(""));
                    }
                }
            }
        }

        private Chart GetChart()
        {
            Chart visual = null;
            if (this.Renderer != null)
            {
                visual = this.Renderer.Visual as Chart;
            }
            return visual;
        }

        internal double GetPointSum(int pi)
        {
            double num = 0.0;
            foreach (DataSeries series in this.Children)
            {
                double[,] values = series.GetValues();
                if (values != null)
                {
                    int length = values.GetLength(1);
                    if (pi < length)
                    {
                        num += values[0, pi];
                    }
                }
            }
            return num;
        }

        private void HandleMouseEvent(object sender, MouseEventArgs e)
        {
            ICollectionView itemsSource = this.ItemsSource as ICollectionView;
            PlotElement originalSource = e.OriginalSource as PlotElement;
            if (((originalSource != null) && (originalSource.DataPoint != null)) && (originalSource.DataPoint.PointIndex >= 0))
            {
                DataSeries series = originalSource.DataPoint.Series;
                if (series.HasDataSource)
                {
                    ICollectionView view2 = series.ItemsSource as ICollectionView;
                    if (view2 != null)
                    {
                        view2.MoveCurrentToPosition(originalSource.DataPoint.PointIndex);
                    }
                }
                else if (itemsSource != null)
                {
                    itemsSource.MoveCurrentToPosition(originalSource.DataPoint.PointIndex);
                }
            }
        }

        private void ItemsSource_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.FireDataChanged(this, EventArgs.Empty);
        }

        private static void OnItemNamesChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            ChartData sender = (ChartData)obj;
            sender.FireDataChanged(sender, EventArgs.Empty);
        }

        protected virtual void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e)
        {
            INotifyCollectionChanged oldValue = e.OldValue as INotifyCollectionChanged;
            if (oldValue != null)
            {
                oldValue.CollectionChanged -= new NotifyCollectionChangedEventHandler(this.ChartData_CollectionChanged);
            }
            else if (e.OldValue is INotifyPropertyChanged)
            {
                ((INotifyPropertyChanged)e.OldValue).PropertyChanged -= new PropertyChangedEventHandler(this.ItemsSource_PropertyChanged);
            }
            oldValue = e.NewValue as INotifyCollectionChanged;
            if (oldValue != null)
            {
                oldValue.CollectionChanged += new NotifyCollectionChangedEventHandler(this.ChartData_CollectionChanged);
            }
            else if (e.NewValue is INotifyPropertyChanged)
            {
                ((INotifyPropertyChanged)e.NewValue).PropertyChanged += new PropertyChangedEventHandler(this.ItemsSource_PropertyChanged);
            }
            ICollectionView newValue = e.OldValue as ICollectionView;
            if (newValue != null)
            {
                newValue.CurrentChanged -= new EventHandler(this.CollectionViewCurrentChanged);
            }
            newValue = e.NewValue as ICollectionView;
            if (newValue != null)
            {
                newValue.CurrentChanged += new EventHandler(this.CollectionViewCurrentChanged);
                this.UpdateSelection(true);
            }
            this.FireDataChanged(this, EventArgs.Empty);
        }

        private static void OnItemsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            ((ChartData)obj).OnItemsSourceChanged(e);
        }

        protected virtual void OnRendererChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.OldValue != null)
            {
                ((IRenderer)e.OldValue).Changed -= new EventHandler(this.FireDataChanged);
            }
            if (e.NewValue != null)
            {
                ((IRenderer)e.NewValue).Dirty = true;
                ((IRenderer)e.NewValue).Changed += new EventHandler(this.FireDataChanged);
            }
            IRenderer oldValue = e.OldValue as IRenderer;
            if (oldValue != null)
            {
                oldValue.Rendered -= new EventHandler(this.rend_Rendered);
                this.DetachHandlers();
            }
            oldValue = e.NewValue as IRenderer;
            if (oldValue != null)
            {
                oldValue.Rendered += new EventHandler(this.rend_Rendered);
            }
            this.FireDataChanged(this, EventArgs.Empty);
        }

        private static void OnRendererChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            ((ChartData)obj).OnRendererChanged(e);
        }

        private static void OnSelectionActionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ChartData data = (ChartData)obj;
            if (data.SelectionAction == SelectionAction.None)
            {
                data.DetachHandlers();
            }
            else
            {
                data.AttachHandlers();
            }
        }

        private static void OnSeriesItemsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ChartData data = (ChartData)obj;
            INotifyCollectionChanged oldValue = args.OldValue as INotifyCollectionChanged;
            if (oldValue != null)
            {
                oldValue.CollectionChanged -= new NotifyCollectionChangedEventHandler(data.SeriesItemsCollectionChanged);
            }
            oldValue = args.NewValue as INotifyCollectionChanged;
            if (oldValue != null)
            {
                oldValue.CollectionChanged += new NotifyCollectionChangedEventHandler(data.SeriesItemsCollectionChanged);
            }
            data.SyncSeries();
        }

        private static void OnSeriesItemTemplateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((ChartData)obj).SyncSeries();
        }

        internal void RemoveSeries(IDataSeriesInfo ser)
        {
            DataSeries series = (DataSeries)ser;
            series.ParentData = null;
            series.PropertyChanged -= new PropertyChangedEventHandler(this.ChartData_PropertyChanged);
        }

        private void rend_Rendered(object sender, EventArgs e)
        {
            this.UpdateSelection(false);
            this.AttachHandlers();
        }

        internal void Reset()
        {
            this.Children.Clear();
            this.ItemNameBinding = null;
            this.ItemNames = null;
            this.ItemsSource = null;
            this.ItemNamesInternal = null;
        }

        private void SeriesItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.SyncSeries();
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeChildren()
        {
            return true;
        }

        private void SyncSeries()
        {
            Chart chart = this.GetChart();
            if (chart != null)
            {
                chart.BeginUpdate();
            }
            this.Children.Clear();
            if ((this.SeriesItemsSource != null) && (this.SeriesItemTemplate != null))
            {
                foreach (object obj2 in this.SeriesItemsSource)
                {
                    DataSeries item = this.SeriesItemTemplate.LoadContent() as DataSeries;
                    if (item != null)
                    {
                        item.DataContext = obj2;
                        this.Children.Add(item);
                    }
                }
            }
            if (chart != null)
            {
                chart.EndUpdate();
            }
        }

        internal void UpdateSelection(bool usePrevious = true)
        {
            ICollectionView itemsSource = this.ItemsSource as ICollectionView;
            if (itemsSource != null)
            {
                int previousIndex = usePrevious ? this.currentIndex : -1;
                this.currentIndex = itemsSource.CurrentPosition;
                int count = this.Children.Count;
                for (int i = 0; i < count; i++)
                {
                    DataSeries series = this.Children[i];
                    if (!series.HasDataSource)
                    {
                        series.UpdateSelectedElement(previousIndex, this.currentIndex);
                    }
                }
            }
            else
            {
                int num4 = this.Children.Count;
                for (int j = 0; j < num4; j++)
                {
                    DataSeries series2 = this.Children[j];
                    series2.nloaded = 0;
                    if (series2.HasDataSource)
                    {
                        series2.UpdateSelection(usePrevious);
                    }
                }
            }
        }

        // Properties
        internal Aggregate Aggregate { get; set; }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public DataSeriesCollection Children
        {
            get
            {
                if (this._children == null)
                {
                    this._children = new DataSeriesCollection(this);
                    this._children.Changed += new EventHandler(this._children_Changed);
                }
                return this._children;
            }
        }

        [DefaultValue((string)null)]
        public Binding ItemNameBinding
        {
            get
            {
                return this._nameBinding;
            }
            set
            {
                if (this._nameBinding != value)
                {
                    this._namesInternal = null;
                    this._nameBinding = value;
                    this.FireDataChanged(this, EventArgs.Empty);
                }
            }
        }

        public IEnumerable ItemNames
        {
            get
            {
                return (IEnumerable)base.GetValue(ItemNamesProperty);
            }
            set
            {
                base.SetValue(ItemNamesProperty, value);
            }
        }

        internal object[] ItemNamesInternal
        {
            get
            {
                if (this.ItemNames == null)
                {
                    return this._namesInternal;
                }
                if (this.ItemNames is string)
                {
                    return ((string)this.ItemNames).Split(null);
                }
                return Utils.CreateArray(this.ItemNames);
            }
            set
            {
                this._namesInternal = value;
            }
        }

        public IEnumerable ItemsSource
        {
            get
            {
                return (IEnumerable)base.GetValue(ItemsSourceProperty);
            }
            set
            {
                base.SetValue(ItemsSourceProperty, value);
            }
        }

        public PlotElementAnimation LoadAnimation
        {
            get
            {
                return (PlotElementAnimation)base.GetValue(LoadAnimationProperty);
            }
            set
            {
                base.SetValue(LoadAnimationProperty, value);
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
        public IRenderer Renderer
        {
            get
            {
                return (IRenderer)base.GetValue(RendererProperty);
            }
            set
            {
                base.SetValue(RendererProperty, value);
            }
        }

        public SelectionAction SelectionAction
        {
            get
            {
                return (SelectionAction)base.GetValue(SelectionActionProperty);
            }
            set
            {
                base.SetValue(SelectionActionProperty, value);
            }
        }

        public IEnumerable SeriesItemsSource
        {
            get
            {
                return (IEnumerable)base.GetValue(SeriesItemsSourceProperty);
            }
            set
            {
                base.SetValue(SeriesItemsSourceProperty, value);
            }
        }

        public DataTemplate SeriesItemTemplate
        {
            get
            {
                return (DataTemplate)base.GetValue(SeriesItemTemplateProperty);
            }
            set
            {
                base.SetValue(SeriesItemTemplateProperty, value);
            }
        }
    }
}
